package com.ihy.controller;

import com.alibaba.fastjson.JSONObject;
import com.ihy.entity.QQUser;
import com.ihy.service.ServiceQQUser;
import com.ihy.utils.AgentUserKit;
import com.ihy.utils.QQHttpClient;
import com.ihy.utils.RedisTemplateUtil;
import com.ihy.utils.ServiceStatusUtil;
import com.ihy.vo.ResultResponse;
import org.apache.http.HttpEntity;
import org.apache.http.ParseException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.*;

/**
 * qq登录前端处理程序
 * <p>
 * Controller注解:
 * 用于标记在一个类上，使用它标记的类就是一个SpringMVC Controller 对象。
 * 分发处理器将会扫描使用了该注解的类的方法，并检测该方法是否使用了@RequestMapping注解。
 * Controller注解只是定义了一个控制器类，而使用@RequestMapping 注解的方法才是真正处理请求的处理器。
 * <p>
 * CrossOrigin注解：
 * 出于安全原因，浏览器禁止Ajax调用驻留在当前原点之外的资源。例如，当你在一个标签中检查你的银行账户时，你可以在另一个选项卡上拥有EVILL网站。
 * 来自EVILL的脚本不能够对你的银行API做出Ajax请求（从你的帐户中取出钱！）使用您的凭据。
 * 跨源资源共享（CORS）是由大多数浏览器实现的W3C规范，允许您灵活地指定什么样的跨域请求被授权，而不是使用一些不太安全和不太强大的策略，如IFRAME或JSONP。
 * <p>
 * RequestMapping注解：
 * 是一个用来处理请求地址映射的注解，可用于类或方法上。用于类上，表示类中的所有响应请求的方法都是以该地址作为父路径。
 */
@Controller
//处理跨域请求
@CrossOrigin
@RequestMapping("/QQ")
public class QQController {
    //自己的域名
    private final String http = "ihy5201314.cn";
    //qq用户
    private final ServiceQQUser serviceQQUser;
    //redis工具类
    public RedisTemplateUtil redisTemplateUtil;
    //返回到前端的数据
    public ResultResponse resultResponse;

    //构造方法注入
    @Autowired
    public QQController(ServiceQQUser serviceQQUser) {
        this.serviceQQUser = serviceQQUser;
    }

    //set方法注入
    @Autowired
    public void setRedisTemplateUtils(RedisTemplateUtil redisTemplateUtil) {
        this.redisTemplateUtil = redisTemplateUtil;
    }

    //set方法注入
    @Autowired
    public void setResultResponse(ResultResponse resultResponse) {
        this.resultResponse = resultResponse;
    }

    //QQ 授权
    @RequestMapping("/oauth")
    @ResponseBody
    public Serializable qq(HttpServletResponse response, HttpServletRequest request, Boolean state) {
        Map<String, String> map = AgentUserKit.getOsAndBrowserInfo(request);
        // 自己注册的回调地址  第一个qq为项目名 第二个qq为QQController定义的@RequestMapping("/qq")第三个为方法  @RequestMapping("/callback")
        //String backUrl = http +"/IHY/QQ/callback";
        String backUrl = "http://localhost:8989/IHY/QQ/callback";
        String ip = ServiceStatusUtil.getIpAddr(request);
        String os = map.get("os");
        String browser = map.get("browser");
        String id = (String) redisTemplateUtil.get(os + "_" + browser + "_" + ip + "_qqState");
        String uuid = "";
        if (id == null || id.equals("")) {
            //去掉uuid中 ”-“ 号
            uuid = UUID.randomUUID().toString().replaceAll("-", "");
            //存储uuid值到redis
            redisTemplateUtil.set(os + "_" + browser + "_" + ip + "_qqState", uuid, 2000);
        }
        // Step1: 获取Authorization Code
        String url = null;
        try {
            url = "https://graph.qq.com/oauth2.0/authorize?response_type=code" +
                    //客户端标识
                    "&client_id=" + QQHttpClient.APPID +
                    //重定向地址
                    "&redirect_uri=" + URLEncoder.encode(backUrl, "UTF-8") +
                    //状态值
                    "&state=" + uuid;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        if (state) {
            // 获得Http客户端(可以理解为:你得先有一个浏览器;注意:实际上HttpClient与浏览器是不一样的)
            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
            // 创建Get请求
            HttpGet httpGet = new HttpGet(url);
            // 响应模型
            CloseableHttpResponse response1;
            // 从响应模型中获取响应实体
            HttpEntity responseEntity;
            try {
                // 由客户端执行(发送)Get请求
                response1 = httpClient.execute(httpGet);
                // 从响应模型中获取响应实体
                responseEntity = response1.getEntity();
                if (responseEntity != null) {
                    response.getWriter().write(EntityUtils.toString(responseEntity));
                }
            } catch (IOException | ParseException e) {
                resultResponse.setCode(500);
                resultResponse.setMessage(e.getMessage());
                return resultResponse;
            }
        } else {
            return url;
        }
        return null;
    }

    /**
     * <html>
     * <head>
     * <meta charset="UTF-8">
     * <title>Insert title here</title>
     * </head>
     * <body>
     * <h1>QQ第一次授权，请绑定帐号</h1>
     * <div>
     *     ${userEntity.nickname}
     * </div>
     * <div>
     *     <img src="${userEntity.image}">
     * </div>
     * <form action="<%=path%>/indexController/regsave" method="post">
     *     <input type="hidden" name="openid" value="${userEntity.openid}" />
     *     <div>电话:<input type="text" name="phone" value="" /></div>
     *     <div>邮件:<input type="text" name="email" value="" /></div>
     *     <div><input type="submit" /></div>
     * </form>
     * </body>
     * </html>
     */

    //QQ 回调
    @RequestMapping("/callback")
    /*
     * @RequestParam注解获取url传递的参数。 例如：/getParam/index2？a=234，结果a=234。
     */
    public Serializable qqCallback(HttpServletRequest request, @RequestParam(value = "code") String code, @RequestParam(value = "state") String state) throws IOException {
        Map<String, String> map = AgentUserKit.getOsAndBrowserInfo(request);
        String ip = ServiceStatusUtil.getIpAddr(request);
        String os = map.get("os");
        String browser = map.get("browser");
        String uuid = (String) redisTemplateUtil.get(os + "_" + browser + "_" + ip + "_qqState");
        if (uuid != null) {
            if (!uuid.equals(state)) {
                throw new AccessDeniedException("TOKEN错误, 防止CSRF攻击当前操作已被禁止。");
            }
        } else {
            throw new AccessDeniedException("操作时间已超时, 请重新操作。");
        }
        // Step2: 通过Authorization Code获取Access Token
        String backUrl = "http://localhost:8989/IHY/QQ/callback";
        String url = "https://graph.qq.com/oauth2.0/token?grant_type=authorization_code" +
                "&client_id=" + QQHttpClient.APPID +
                "&client_secret=" + QQHttpClient.APPKEY +
                "&code=" + code +
                "&redirect_uri=" + backUrl;
        String access_token = QQHttpClient.getAccessToken(url);
        // Step3: 获取回调后的 openid 值
        url = "https://graph.qq.com/oauth2.0/me?access_token=" + access_token;
        String openid = QQHttpClient.getOpenID(url);
        // Step4: 获取QQ用户信息
        url = "https://graph.qq.com/user/get_user_info?access_token=" + access_token +
                "&oauth_consumer_key=" + QQHttpClient.APPID +
                "&openid=" + openid;
        JSONObject jsonObject = QQHttpClient.getUserInfo(url);
        // 也可以放到Redis中或MySQL中
        /*session.setAttribute("openid", openid);
        session.setAttribute("nickname", (String)jsonObject.get("nickname"));
        session.setAttribute("figureurl_qq_2", (String)jsonObject.get("figureurl_qq_2"));
        openid = "2";*/
        // 绑定数据库， 如果没有QQ授权过的注册一个帐号
        QQUser userEntity = serviceQQUser.getOpenid(openid);
        if (userEntity == null) {
            userEntity = new QQUser();
            String uuids = UUID.randomUUID().toString().replaceAll("-", "");
            userEntity.setUid(uuids);
            userEntity.setOpenid(openid);
            userEntity.setName((String) jsonObject.get("name"));
            userEntity.setImage((String) jsonObject.get("figureurl_qq_2"));
            //userEntity.setName("name");
            //userEntity.setImage("figureurl_qq_2");
            userEntity.setUsername(null);
            userEntity.setPassword(null);
            serviceQQUser.insert(userEntity);
        } else {
            userEntity.setName((String) jsonObject.get("name"));
            userEntity.setImage((String) jsonObject.get("figureurl_qq_2"));
            //userEntity.setName("name");
            //userEntity.setImage("figureurl_qq_2");
            userEntity.setUsername(null);
            userEntity.setPassword(null);
            serviceQQUser.update(userEntity);
            redisTemplateUtil.set(os + "_" + browser + "_" + ip + "_openid", userEntity.getOpenid());
        }
        return home(request);
    }

    /**
     * 第二次登录
     * <html>
     * <head>
     * <meta charset="UTF-8">
     * <title>Insert title here</title>
     * </head>
     * <body>
     * <#--
     *         <div>QQ授权成功</div>
     *         <div>
     *             OPENID: ${openid}
     *         </div>
     *         <div>
     *             NickName: ${nickname}
     *         </div>
     *         <div>
     *             <img src="${figureurl_qq_2}">
     *         </div>
     *         -->
     *
     *         <div>QQ授权成功</div>
     *         <div>
     *             ${userEntity.nickname}
     *         </div>
     *         <div>
     *             <img src="${userEntity.image}">
     *         </div>
     *         <div>
     *             ${userEntity.email?}
     *         </div>
     *
     *     </body>
     * </html>
     */
    @RequestMapping("/home")
    @ResponseBody
    public Serializable home(HttpServletRequest request) {
        Map<String, String> map = AgentUserKit.getOsAndBrowserInfo(request);
        String ip = ServiceStatusUtil.getIpAddr(request);
        String os = map.get("os");
        String browser = map.get("browser");
        String openid = (String) redisTemplateUtil.get(os + "_" + browser + "_" + ip + "_openid");
        if (openid != null) {
            QQUser userEntity = serviceQQUser.getOpenid(openid);
            //StringUtils.isEmpty(userEntity.getPassword() 过时的方法
            if (StringUtils.hasText(userEntity.getPassword())) {
                //看看是否有密码，如果没有到register可以在给这个qq登陆设置一个密码，添加邮箱。。。
                return register(request, openid);
            }
            redisTemplateUtil.set(os + "_" + browser + "_" + ip + "_userEntity", userEntity, 2000);
        }
        resultResponse.setCode(200);
        resultResponse.setMessage("home");
        return resultResponse;
    }

    //注册
    @RequestMapping("/register")
    @ResponseBody
    public Serializable register(HttpServletRequest request, String openid) {
        Map<String, String> map = AgentUserKit.getOsAndBrowserInfo(request);
        String ip = ServiceStatusUtil.getIpAddr(request);
        String os = map.get("os");
        String browser = map.get("browser");
        QQUser userEntity = serviceQQUser.getOpenid(openid);
        redisTemplateUtil.set(os + "_" + browser + "_" + ip + "_userEntity", userEntity, 2000);
        resultResponse.setCode(200);
        resultResponse.setMessage("register");
        return resultResponse;
    }
}